package model.doe;

public class ElongFocusFocusator extends AbstractDoe {

	private double rad;
	private double f;
	private double wl;
	private double x;
	private double step;
	private boolean addLen;
	private double d;
	private double k;
	private double c;
	private double foc;
	private double min1;
	private double max1;
	private double fi0;

	public ElongFocusFocusator(double rad, double f, double wl, double x, double step, boolean addLen) {
		this.rad = rad;
		this.f = f;
		this.wl = wl;
		this.x = x;
		this.step = step;
		this.addLen = addLen;

		super.widthPointsNumber = (int) (2*rad / step);
		super.heightPointsNumber = (int) (2*rad / step);
		
		linl_init( x, wl/1000,rad,f);
	}

	private double calculate (double u, double v){
		double r = Math.sqrt(u * u + v * v);
		if (r>rad) {
			return 0;
		}
		if (addLen){			
			return linl0_full(r);
		}
		else {
			return linl1_full(r);
		}
	}
	
	void linl_init(double x, double wl, double radius,double focus) {

		// ************ Parameter initialization
		// ************************************

		int N = 64, i;

		double res, h = radius / N;

		d = 2 * radius;

		k = 2 * Math.PI / wl;

		c = 4 * x / (d * d);

		foc = focus;

		if (!addLen) {

			super.minValue = super.maximumValue = linl1(0);

			for (i = 0; i < N; i++) {

				res = linl1(h * i);

				if (super.minValue > res)
					super.minValue = res;

				if (super.maximumValue < res)
					super.maximumValue = res;

			}

		}

		else {
			super.minValue = super.maximumValue = linl0(0);

			for (i = 0; i < N; i++) {

				res = linl0(h * i);

				if (super.minValue > res)
					super.minValue = res;

				if (super.maximumValue < res)
					super.maximumValue = res;
			}
		}

		fi0 = max1;
		
		super.maximumValue = super.maximumValue-minValue ;
		minValue = 0;
		
		return;
	}

	// --------------------------------------------------------------------------

	double linl1(double r) {

		// *********** Phase function when focusator as addition to lens
		// ************

		double fi;

		fi = k
				/ (2 * c)
				* Math.log(2 * c * Math.sqrt(r * r + (foc - c * r * r) * (foc - c * r * r)) + 2 * c * c * r * r + 1 - 2
						* foc * c);

		return fi;
	}

	// --------------------------------------------------------------------------

	double linl0(double r) {

		// ********** Phase function when focusator contain lens function
		// ************

		double fi;

		fi = k
				/ (2 * c)
				* Math.log(2 * c * Math.sqrt(r * r + (foc - c * r * r) * (foc - c * r * r)) + 2 * c * c * r * r + 1 - 2
						* foc * c) +

				k * (Math.sqrt(r * r + foc * foc) - foc);

		return fi;
	}

	// __________________________________________________________________________

	double linl1_full(double r) {

		double fi;

		fi = fi0 - linl1(r);

		return fi;
	}

	// _____________________________________________________________________________

	double linl0_full(double r) {

		double fi;

		fi = fi0 - linl0(r);

		return fi;
	}

	@Override
	public double run(int i, int j) {		
		return calculate(step * i, step * j);
	}
}
